package com.bjy.qa.util.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.bjy.qa.exception.MyException;
import com.bjy.qa.util.redis.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT 过滤器
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver; // 注入全局异常处理器

    @Resource
    RedisUtil redisUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader("token"); // 从 request head 中获取 token

        // 如果 token 为空，则直接放行。交给后续处理，对应资源是否需要登录，需要抛异常，不需要则直接放行
        if (StringUtils.isBlank(token)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        // 解码jwt并的到user id
        long userId;
        try {
            DecodedJWT decodedJWT = JWT.decode(token);
            userId = decodedJWT.getClaim("id").asLong();
        } catch (Exception e) {
            resolver.resolveException(httpServletRequest, httpServletResponse, null, new MyException("token解析失败！"));
            return;
        }

        // 从redis中获取用户信息
        String redisKey = "qap:login:userId:" + userId;
        LoginUser loginUser = (LoginUser) redisUtil.get(redisKey);
        if (loginUser == null) {
            resolver.resolveException(httpServletRequest, httpServletResponse, null, new MyException("用户未登录！"));
            return;
        }

        // 存入 SecurityContextHolder
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

        // 放行
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}
